import requests
import json
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from apps.web.forms.manage import FileModelForm, PerFileModelForm
from apps.web import models
from tools import cos
from django.urls import reverse

def file_list(request, project_id):
    parent_obj = None
    folder_id = request.GET.get('folder', '')
    # 当前目录文件&文件夹
    if folder_id.isdecimal():
        parent_obj = models.FileRepository.objects.filter(id=int(folder_id), file_type=2,
                                                          project=request.tracer.project).first()

    if request.method == 'GET':
        # 导航条的显示
        nav_list = []
        parent = parent_obj
        while parent:
            nav_list.insert(0, {'id': parent.id, 'name': parent.name})
            parent = parent.parent
        # 当前目录下的文件&文件夹显示出来
        queryset = models.FileRepository.objects.filter(project=request.tracer.project)
        if parent_obj:
            file_obj_list = queryset.filter(parent=parent_obj).order_by('-file_type')
        else:
            file_obj_list = queryset.filter(parent__isnull=True).order_by('-file_type')

        form = FileModelForm(request, parent_obj)
        context = {
            'form': form,
            'file_obj_list': file_obj_list,
            'nav_list': nav_list,
            'folder_obj': parent_obj,
        }
        return render(request, 'web/file_list.html', context)
    # post请求时
    # 添加文件夹 & 修改
    fid = request.POST.get('fid', '')
    edit_obj = None
    if fid.isdecimal():
        # 修改
        # 获取到当前fid的对象
        edit_obj = models.FileRepository.objects.filter(id=int(fid), file_type=2,
                                                        project=request.tracer.project).first()

    if edit_obj:
        form = FileModelForm(request, parent_obj, data=request.POST, instance=edit_obj)
    else:
        form = FileModelForm(request, parent_obj, data=request.POST)
    if form.is_valid():
        form.instance.project = request.tracer.project
        form.instance.file_type = 2
        form.instance.update_user = request.tracer.user
        form.instance.parent = parent_obj
        # 保存到数据库
        form.save()
        return JsonResponse({'status': True})
    return JsonResponse({'status': False, 'error': form.errors})


def file_delete(request, project_id):
    """
    删除文件夹
    :param request:
    :param project_id:
    :return:
    """
    # 获取当前传入的fid
    fid = request.GET.get('fid')
    delete_obj = models.FileRepository.objects.filter(id=fid, project=request.tracer.project).first()
    if delete_obj.file_type == 1:
        # 删除文件(数据库&cos都得删除), 已使用的容量进行返回
        # 删除文件时将容量返回
        request.tracer.project.use_space -= delete_obj.file_size
        # 保存当前容量
        request.tracer.project.save()
        # cos删除文件
        cos.delete_file(request.tracer.project.region, request.tracer.project.bucket, delete_obj.key)
        # 数据库中删除文件
        delete_obj.delete()
        return JsonResponse({'status': True})
    else:
        # 删除文件夹(找到数据库该文件夹下所有的文件，每个文件进行数据库&cos都得删除, 已使用的容量进行返回)
        # 查询当前对象下所有的文件&文件夹
        # 查到文件直接删除归还容量，查到文件夹还得继续查询该文件夹下的文件&文件夹
        total_size = 0  # 要删除的总大小
        folder_list = [delete_obj, ]  # 存放要循环的文件夹
        key_list = []  # 要删除的文件
        # 循环每一个文件夹
        for folder in folder_list:
            # 查询每一个文件夹里面的文件&文件夹
            child_list = models.FileRepository.objects.filter(project=request.tracer.project, parent=folder).order_by(
                '-file_type')
            for child in child_list:
                if child.file_type == 2:
                    # 文件夹添加到列表
                    folder_list.append(child)
                else:
                    # 查询为文件
                    total_size += child.file_size  # 汇总文件大小
                    # cos删除文件
                    key_list.append({'key': child.key})
        # cos批量删除文件
        if key_list:
            cos.delete_file_list(request.tracer.project.region, request.tracer.project.bucket, key_list)
        # 归还容量
        if total_size:
            request.tracer.project.use_space -= total_size
            # 保存当前容量
            request.tracer.project.save()
        # 删除数据库文件
        delete_obj.delete()
        return JsonResponse({'status': True})


@csrf_exempt
def cos_credential(request, project_id):
    """
    获取临时凭证
    :param request:
    :param project_id:
    :return:
    """
    # 单文件限制
    per_file_limit = request.tracer.price_policy.per_file_size * 1024 * 1024
    # 总容量限制
    total_file_limit = request.tracer.price_policy.project_space * 1024 * 1024 * 1024
    # 总文件容量
    total_size = 0
    # 前端传过来一个JSON,需要解码
    file_list = json.loads(request.body.decode('utf-8'))
    for item in file_list:
        # 上传文件的字节大小 item['size'] 多少B, MB需要转换
        if item['size'] > per_file_limit:
            msg = '单文件超出限制(最大为{}M), 文件: {}，请升级套餐'.format(request.tracer.price_policy.per_file_size, item['name'])
            return JsonResponse({'status': False, 'error': msg})
        # 总容量限制
        total_size += item['size']
    if total_size > total_file_limit - request.tracer.project.use_space:
        return JsonResponse({'status': False, 'error': '容量超出限制，请升级套餐'})
    data = cos.credential(request.tracer.project.bucket, request.tracer.project.region)
    return JsonResponse({'status': True, 'data': data})


# @csrf_exempt
# def file_post(request, project_id):
#     """
#     上传成功的文件写入到数据库
#     :param request:
#     :param project_id: 项目id
#     :return:
#     """
#     form = PerFileModelForm(request, data=request.POST)
#     if form.is_valid():
#         # 校验通过，写入到数据库 ,form.save() 无法获取get_xx_display
#         # form.instance.file_type = 1
#         # form.instance.project = request.tracer.project
#         # form.instance.update_user = request.tracer.user
#         # form.save()
#         # 拿到前端传过来的字典
#         """
#         'name': fileName,
#         'file_size': fileSize,
#         'key': key,
#         'parent': '{{ folder_obj.id }}',
#         'etag': data.ETag,
#         'file_path': data.Location
#         """
#         data_dict = form.cleaned_data
#         data_dict.pop('etag')  # 删除etag是因为数据库并没有添加这个字段
#         # 加上数据库其他字段
#         data_dict.update({'project': request.tracer.project, 'file_type': 1, 'update_user': request.tracer.user})
#         # 写入数据库
#         instance = models.FileRepository.objects.create(**data_dict)
#
#         # 更新项目已使用空间
#         print('单文件', data_dict['file_size'])
#         request.tracer.project.use_space += data_dict['file_size']
#         request.tracer.project.save()
#         print('项目使用空间', request.tracer.project.use_space)
#         res = {
#             'name': instance.name,
#             'file_type': instance.get_file_type_display(),
#             'file_size': instance.file_size,
#             'update_user_usernmae': instance.update_user.username,
#             'update_datetime': instance.update_datetime.strftime('%Y年%m月%d日 %H:%M'),
#             'id': instance.id
#         }
#         return JsonResponse({'status': True, 'data': res})
#     return JsonResponse({'status': False, 'error': form.errors})


from django.db import transaction
from django.db.models import F


@csrf_exempt
def file_post(request, project_id):
    """
    上传成功的文件写入到数据库
    """
    form = PerFileModelForm(request, data=request.POST)
    if form.is_valid():
        data_dict = form.cleaned_data
        data_dict.pop('etag')
        data_dict.update({'project': request.tracer.project, 'file_type': 1, 'update_user': request.tracer.user})

        # 使用事务确保原子性
        with transaction.atomic():
            # 使用F表达式进行原子性更新，避免并发问题
            project = models.Project.objects.select_for_update().get(id=request.tracer.project.id)
            project.use_space = F('use_space') + data_dict['file_size']
            project.save()

            # 写入数据库
            instance = models.FileRepository.objects.create(**data_dict)

        # 重新获取更新后的值用于返回
        request.tracer.project.refresh_from_db()

        res = {
            'name': instance.name,
            'file_type': instance.get_file_type_display(),
            'file_size': instance.file_size,
            'update_user_username': instance.update_user.username,
            'update_datetime': instance.update_datetime.strftime('%Y年%m月%d日 %H:%M'),
            'id': instance.id,
            'download_url': reverse('manage:file_download', kwargs={'project_id': project_id, 'file_id': instance.id})
        }
        return JsonResponse({'status': True, 'data': res})
    return JsonResponse({'status': False, 'error': form.errors})


def file_download(request, project_id, file_id):
    """下载文件"""
    # 查找当前文件对象
    file_obj = models.FileRepository.objects.filter(project_id=project_id, id=file_id).first()

    # 打开文件，获取文件内容
    res = requests.get(file_obj.file_path)

    data = res.content  # 获取到文件内容
    response = HttpResponse(data)
    # 设置响应头
    response['Content-Disposition'] = 'attachment; filename={}'.format(file_obj.name)
    return response
